home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
irsim-ca.2
/
irsim-ca
/
irsim-cap-9.2
/
src
/
irsim
/
network.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-20
|
12KB
|
552 lines
/*
* *********************************************************************
* * Copyright (C) 1988, 1990 Stanford University. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. Stanford University *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#include <stdio.h>
#include "defs.h"
#include "net.h"
#include "globals.h"
/* event driven mosfet simulator. Chris Terman (2/80) */
public iptr hinputs = NULL; /* list of nodes to be driven high */
public iptr linputs = NULL; /* list of nodes to be driven low */
public iptr uinputs = NULL; /* list of nodes to be driven X */
public iptr xinputs = NULL; /* list of nodes to be removed from input */
public iptr infree = NULL; /* unused input list cells */
public iptr *listTbl[8];
public
#define FreeInput( X ) (X)->next = infree, infree = (X)
public void init_listTbl()
{
int i;
for( i = 0; i < 8; listTbl[ i++ ] = NULL );
listTbl[ INPUT_NUM( H_INPUT ) ] = &hinputs;
listTbl[ INPUT_NUM( L_INPUT ) ] = &linputs;
listTbl[ INPUT_NUM( U_INPUT ) ] = &uinputs;
listTbl[ INPUT_NUM( X_INPUT ) ] = &xinputs;
}
#define pvalue( node_name, node ) \
lprintf( stdout, "%s=%c ", (node_name), "0XX1"[(node)->npot] )
private void pgvalue( t )
register tptr t;
{
register nptr n;
static char *states[] = { "OFF", "ON", "UKNOWN", "WEAK" };
if( debug )
lprintf( stdout, "[%s] ", states[t->state] );
if( t->ttype & GATELIST )
{
lprintf( stdout, "( " );
for( t = (tptr) t->gate; t != NULL; t = t->scache.t )
{
n = t->gate;
pvalue( pnode( n ), n );
}
lprintf( stdout, ") " );
}
else
{
n = t->gate;
pvalue( pnode( n ), n );
}
}
private void pr_one_res( s, r )
char *s;
double r;
{
if( r < 1e-9 or r > 100e9 )
(void) sprintf( s, "%2.1e", r );
else
{
int e = 3;
if( r >= 1000.0 )
do { e++; r *= 0.001; } while( r >= 1000.0 );
else if( r < 1 and r > 0 )
do { e--; r *= 1000; } while( r < 1.0 );
(void) sprintf( s, "%.1f%c", r, "num\0KMG"[ e ] );
}
}
private void pr_t_res( fp, r )
FILE *fp;
Resists *r;
{
char buf[3][15];
pr_one_res( buf[0], r->rstatic );
pr_one_res( buf[1], r->dynhigh );
pr_one_res( buf[2], r->dynlow );
lprintf( fp, "[%s, %s, %s]", buf[0], buf[1], buf[2] );
}
private void ptrans( t )
register tptr t;
{
lprintf( stdout, "%s ", ttype[ BASETYPE( t->ttype ) ] );
if( BASETYPE( t->ttype ) != RESIST )
pgvalue( t );
pvalue( pnode( t->source ), t->source );
pvalue( pnode( t->drain ), t->drain );
pr_t_res( stdout, t->r );
if( t->tlink != t and (treport & REPORT_TCOORD) )
lprintf( stdout, " <%d,%d>\n", t->x.pos, t->y.pos );
else
lprintf( stdout, "\n" );
}
public void idelete( n, list )
register nptr n;
register iptr *list;
{
register iptr p = *list;
register iptr q;
if( p == NULL )
return;
else if( p->inode == n )
{
*list = p->next;
FreeInput( p );
}
else
{
for( q = p->next; q != NULL; p = q, q = p->next )
if( q->inode == n )
{
p->next = q->next;
FreeInput( q );
return;
}
}
}
public void iinsert( n, list )
nptr n;
iptr *list;
{
register iptr p = infree;
if( p == NULL )
p = infree = (iptr) MallocList( sizeof( struct Input ), 1 );
infree = p->next;
p->next = *list;
*list = p;
p->inode = n;
}
public void iinsert_once( n, list )
nptr n;
iptr *list;
{
register iptr p;
for( p = *list; p != NULL; p = p->next )
if( p->inode == n )
return;
iinsert( n, list );
}
private int clear_input( n )
register nptr n;
{
if( not( n->nflags & POWER_RAIL ) )
n->nflags &= ~INPUT;
return( 0 );
}
public void ClearInputs()
{
register int i;
register iptr p, next;
register nptr n;
for( i = 0; i < 5; i++ )
{
if( listTbl[ i ] == NULL )
continue;
for( p = *listTbl[ i ]; p != NULL; p = next )
{
next = p->next;
n = p->inode;
FreeInput( p );
if( not( n->nflags & POWER_RAIL ) )
n->nflags &= ~(INPUT_MASK | INPUT);
}
*(listTbl[ i ]) = NULL;
}
walk_net( clear_input, (char *) 0 );
}
/*
* set/clear input status of node and add/remove it to/from corresponding list.
*/
public int setin( n, which )
register nptr n;
char *which;
{
while( n->nflags & ALIAS )
n = n->nlink;
if( n->nflags & (POWER_RAIL | MERGED) ) /* Gnd, Vdd, or merged node */
{
if( (n->nflags & MERGED) or "lxuh"[ n->npot ] != *which )
lprintf( stdout, "Can't drive `%s' to `%c'\n",
pnode( n ), *which );
}
else
{
iptr *list = listTbl[ INPUT_NUM( n->nflags ) ];
# define WASINP( N, P ) ( ((N)->nflags & INPUT) && (N)->npot == (P) )
switch( *which )
{
case 'h' :
if( list != NULL and list != &hinputs )
{
n->nflags = n->nflags & ~INPUT_MASK;
idelete( n, list );
}
if( not (list == &hinputs or WASINP( n, HIGH )) )
{
n->nflags = (n->nflags & ~INPUT_MASK) | H_INPUT;
iinsert( n, &hinputs );
}
break;
case 'l' :
if( list != NULL and list != &linputs )
{
n->nflags = n->nflags & ~INPUT_MASK;
idelete( n, list );
}
if( not (list == &linputs or WASINP( n, LOW )) )
{
n->nflags = (n->nflags & ~INPUT_MASK) | L_INPUT;
iinsert( n, &linputs );
}
break;
case 'u' :
if( list != NULL and list != &uinputs )
{
n->nflags = n->nflags & ~INPUT_MASK;
idelete( n, list );
}
if( not (list == &uinputs or WASINP( n, X )) )
{
n->nflags = (n->nflags & ~INPUT_MASK) | U_INPUT;
iinsert( n, &uinputs );
}
break;
case 'x' :
if( list == &xinputs )
break;
if( list )
{
n->nflags = n->nflags & ~INPUT_MASK;
idelete( n, list );
}
if( n->nflags & INPUT )
{
n->nflags = (n->nflags & ~INPUT_MASK) | X_INPUT;
iinsert( n, &xinputs );
}
break;
default :
return( 0 );
}
}
return( 1 );
}
private int wr_value( n, fp )
register nptr n;
FILE *fp;
{
if( not (n->nflags & (ALIAS | POWER_RAIL)) )
{
int ch = ((n->nflags & INPUT) ? '4' : '0') + n->npot;
(void) putc( ch, fp );
}
return( 0 );
}
public int wr_state( fname )
char *fname;
{
FILE *fp;
if( (fp = fopen( fname, "w" )) == NULL )
return( 1 );
(void) fprintf( fp, "%d\n", nnodes );
walk_net( wr_value, (char *) fp );
(void) fclose( fp );
return( 0 );
}
typedef struct
{
FILE *file;
int errs;
int restore;
} StateFile;
private int rd_stvalue( n, st )
register nptr n;
StateFile *st;
{
int ch, inp;
if( n->nflags & (ALIAS | POWER_RAIL) )
return( 0 );
FreeHistList( n );
while( n->events != NULL ) /* remove any pending events */
free_event( n->events );
if( st->file == NULL )
{
ch = X;
st->errs ++;
}
else
{
ch = getc( st->file );
if( ch == EOF )
{
ch = X;
st->errs ++;
(void) fclose( st->file );
st->file = NULL;
}
else if( ch < '0' or ch > '7' or ch == '2' or ch == '6' )
{
st->errs ++;
ch = X;
}
else if( st->restore and ch >= '4' )
{
ch = ch - '4';
inp = 1;
}
else
{
ch = (ch - '0') & (LOW | X | HIGH);
inp = 0;
}
}
if( n->nflags & MERGED )
return( 0 );
if( inp )
n->nflags |= INPUT;
n->head.val = ch;
n->head.inp = inp;
if( ch != n->npot )
{
register lptr l;
register tptr t;
n->npot = ch;
for( l = n->ngate; l != NULL; l = l->next )
{
t = l->xtor;
t->state = compute_trans_state( t );
}
}
return( 0 );
}
public char *rd_state( fname, restore )
char *fname;
int restore;
{
char rline[25];
StateFile st;
if( (st.file = fopen( fname, "r" )) == NULL )
return( "can not read state file\n" );
(void) fgetline( rline, 25, st.file );
if( atoi( rline ) != nnodes )
{
(void) fclose( st.file );
return( "bad node count in state file\n" );
}
ClearInputs();
if( analyzerON )
StopAnalyzer();
sim_time0 = cur_delta = 0;
st.errs = 0;
st.restore = restore;
walk_net( rd_stvalue, (char *) &st );
NoInit();
if( analyzerON )
RestartAnalyzer( sim_time0, cur_delta, FALSE );
if( st.file == NULL )
{
(void) sprintf( fname, "premature EOF in state file (%d errors)\n",
st.errs );
return( fname );
}
(void) fclose( st.file );
if( st.errs != 0 )
{
(void) sprintf( fname, "%d errors found in state file\n", st.errs );
return( fname );
}
return( NULL );
}
public int info( n, which )
register nptr n;
char *which;
{
register tptr t;
register lptr l;
char *name;
if( n == NULL )
return( 0 );
if( int_received )
return( 1 );
name = pnode( n );
while( n->nflags & ALIAS )
n = n->nlink;
if( n->nflags & MERGED )
{
lprintf( stdout, "%s => node is inside a transistor stack\n", name );
return( 1 );
}
pvalue( name, n );
if( n->nflags & INPUT )
lprintf( stdout, "[NOTE: node is an input] " );
lprintf( stdout, "(vl=%.2f vh=%.2f) ", n->vlow, n->vhigh );
if( n->nflags & USERDELAY )
lprintf( stdout, "(tplh=%d, tphl=%d) ", n->tplh, n->tphl );
lprintf( stdout, "(%4.3f pf) ", n->ncap );
if( *which == '?' )
{
lprintf( stdout, "is computed from:\n" );
for( l = n->nterm; l != NULL and int_received == 0; l = l->next )
{
t = l->xtor;
lprintf( stdout, " " );
if( debug == 0 )
{
char *drive = NULL;
nptr rail;
rail = (t->drain->nflags & POWER_RAIL) ? t->drain : t->source;
if( BASETYPE( t->ttype ) == NCHAN and rail == GND_node )
drive = "pulled down by ";
else if( BASETYPE( t->ttype ) == PCHAN and rail == VDD_node )
drive = "pulled up by ";
else if( BASETYPE( t->ttype ) == DEP and rail == VDD_node and
other_node( t, rail ) == t->gate )
drive = "pullup ";
else
ptrans( t );
if( drive != NULL )
{
lprintf( stdout, drive );
pgvalue( t );
pr_t_res( stdout, t->r );
if( t->tlink != t and (treport & REPORT_TCOORD) )
lprintf( stdout, " <%d,%d>\n", t->x.pos, t->y.pos );
else
lprintf( stdout, "\n" );
}
}
else
ptrans( t );
}
}
else
{
lprintf( stdout, "affects:\n" );
for( l = n->ngate; l != NULL and int_received == 0; l = l->next )
ptrans( l->xtor );
}
if( int_received )
lprintf( stdout, "-- interrupted\n" );
if( n->events != NULL )
{
register evptr e;
lprintf( stdout, "Pending events:\n" );
for( e = n->events; e != NULL; e = e->nlink )
lprintf( stdout, " transition to %c at %2.1fns\n",
"0XX1"[e->eval], d2ns( e->ntime ) );
}
return( 1 );
}